﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Collections;
using System.Xml;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Yahoo.Yui.Compressor;

namespace DNNtc.MSBuild.Tasks
{
    public class BusinessControllerInfo
    {
        public string Class { get; set; }
        public string NameSpace { get; set; }

        public override string ToString()
        {
            const string tab6 = "@tab@@tab@@tab@@tab@@tab@@tab@";
            if (Class == null || NameSpace == null || Class == String.Empty || NameSpace == String.Empty)
                return tab6 + "<businessControllerClass />";
            else
                return tab6 + "<businessControllerClass>" + this.Class + "," + this.NameSpace + "</businessControllerClass>";
        }
    }

    public class AssemblyInfo
    {
        public string Path { get; set; }
        public string FileName { get; set; }

        public override string ToString()
        {
            const string Stab = "@tab@";
            const string Tab = "@tab@@tab@@tab@@tab@@tab@@tab@";

            //Build the element
            StringBuilder sb = new StringBuilder();

            //Output will be in this format for each assembly in "Files"
            //<assembly>
            //  <path>bin</path>
            //  <name>Example.dll</name>
            //</assembly>

            //Create node
            sb.AppendLine(Tab + "<assembly>");
            if (!string.IsNullOrEmpty(Path)) sb.AppendLine(Tab + Stab + "<path>" + this.Path + "</path>");
            sb.AppendLine(Tab + Stab + "<name>" + this.FileName + "</name>");
            sb.Append(Tab + "</assembly>");
            return sb.ToString();
        }
    }

    public class ConfigInfo
    {
        public string Path { get; set; }
        public string Action { get; set; }
        public string Key { get; set; }
        public string Value { get; set; }
        public string Ros { get; set; }
        public string Collision { get; set; }
    }

    public class ConfigEntriesInfo
    {
        public ConfigEntriesInfo()
        {
            Configs = new List<ConfigInfo>();
        }

        public List<ConfigInfo> Configs { get; set; }
        public void Add(ConfigInfo config)
        {
            Configs.Add(config);
        }
        public override string ToString()
        {
            if (Configs.Count == 0)
                return "";

            //<configFile>web.config</configFile>
            //<install>
            //    <configuration>
            //        <nodes>
            //            <node path="Xpath" action="add/insertBefore/insertAfter/remove/removeattribute/update/updateattribute" key="key/name" collision="save/overwrite" >
            //                <add key="myKey" value="" />
            //                <add name="myName" type="myType" providerPath="myPath" />
            //            </node>
            //        </nodes>
            //    </configuration>
            //</install>
            //<uninstall>
            //    <configuration>
            //        <nodes>
            //            <node path="Xpath/add[@key/@name='myKey/MyName']" action="remove" />
            //        </nodes>
            //    </configuration>
            //</uninstall>

            const string tab4 = "@tab@@tab@@tab@@tab@";
            const string tab5 = "@tab@@tab@@tab@@tab@@tab@";
            const string tab6 = "@tab@@tab@@tab@@tab@@tab@@tab@";
            const string tab7 = "@tab@@tab@@tab@@tab@@tab@@tab@@tab@";
            const string tab8 = "@tab@@tab@@tab@@tab@@tab@@tab@@tab@@tab@";
            const string tab9 = "@tab@@tab@@tab@@tab@@tab@@tab@@tab@@tab@@tab@";
            const string tab10 = "@tab@@tab@@tab@@tab@@tab@@tab@@tab@@tab@@tab@@tab@";

            StringBuilder sb = new StringBuilder();
            sb.AppendLine(tab4 + "<component type=\"Config\">");
            sb.AppendLine(tab5 + "<config>");
            sb.AppendLine(tab6 + "<configFile>web.config</configFile>");
            sb.AppendLine(tab6 + "<install>");
            sb.AppendLine(tab7 + "<configuration>");
            sb.AppendLine(tab8 + "<nodes>");

            foreach (ConfigInfo config in Configs)
            {
                sb.AppendLine(tab9 + string.Format("<node path=\"{0}\" action=\"{1}\" key=\"{2}\" collision=\"{3}\" >", config.Path, config.Action, config.Key, config.Collision));
                sb.AppendLine(tab10 + string.Format("<add {0}={1} {2} />", config.Key, config.Value, config.Ros));
                sb.AppendLine(tab9 + "</node>");
            }

            sb.AppendLine(tab8 + "</nodes>");
            sb.AppendLine(tab7 + "</configuration>");
            sb.AppendLine(tab6 + "</install>");

            sb.AppendLine(tab6 + "<uninstall>");
            sb.AppendLine(tab7 + "<configuration>");
            sb.AppendLine(tab8 + "<nodes>");

            foreach (ConfigInfo config in Configs)
            {
                sb.AppendLine(tab9 + string.Format("<node path=\"{0}/add[@{1}={2}]\" action=\"remove\" />", config.Path, config.Key, config.Value.Replace("\"", "'")));
            }

            sb.AppendLine(tab8 + "</nodes>");
            sb.AppendLine(tab7 + "</configuration>");
            sb.AppendLine(tab6 + "</uninstall>");

            sb.AppendLine(tab5 + "</config>");
            sb.Append(tab4 + "</component>");
            return sb.ToString();
        }
    }

    public class EventMessageInfo
    {
        public string BusinessController { get; set; }
        public string UpgradeVersionsList { get; set; }

        public override string ToString()
        {
            if (BusinessController == null || UpgradeVersionsList == null)
                return "";

            //<eventMessage>
            //    <processorType>DotNetNuke.Entities.Modules.EventMessageProcessor, DotNetNuke</processorType>
            //    <processorCommand>UpgradeModule</processorCommand>
            //    <attributes>
            //        <businessControllerClass>DotNetNuke.Modules.Events.EventController, DotNetNuke.Modules.Events
            //        <desktopModuleID>[DESKTOPMODULEID]</desktopModuleID>
            //        <upgradeVersionsList>03.01.00,04.00.02,04.01.00</upgradeVersionsList>
            //    </attributes>
            //</eventMessage>

            const string tab5 = "@tab@@tab@@tab@@tab@@tab@";
            const string tab6 = "@tab@@tab@@tab@@tab@@tab@@tab@";
            const string tab7 = "@tab@@tab@@tab@@tab@@tab@@tab@@tab@";

            StringBuilder sb = new StringBuilder();
            sb.AppendLine();
            sb.AppendLine(tab5 + "<eventMessage>");
            sb.AppendLine(tab6 + "<processorType>DotNetNuke.Entities.Modules.EventMessageProcessor, DotNetNuke</processorType>");
            sb.AppendLine(tab6 + "<processorCommand>UpgradeModule</processorCommand>");
            sb.AppendLine(tab6 + "<attributes>");
            sb.AppendLine(tab7 + String.Format("<businessControllerClass>{0}</businessControllerClass>", BusinessController));
            sb.AppendLine(tab7 + "<desktopModuleID>[DESKTOPMODULEID]</desktopModuleID>");
            sb.AppendLine(tab7 + String.Format("<upgradeVersionsList>{0}</upgradeVersionsList>", UpgradeVersionsList));
            sb.AppendLine(tab6 + "</attributes>");
            sb.Append(tab5 + "</eventMessage>");

            return sb.ToString();
        }
    }

    public class ModulePermissionInfo
    {
        public string Code { get; set; }
        public string Key { get; set; }
        public string Name { get; set; }

        public override string ToString()
        {
            //<permission code="EVENTS_MODULE" key="EVENTSSET" name="Edit Settings" />
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(String.Format("<permission code=\"{0}\" key=\"{1}\" name=\"{2}\" />", Code, Key, Name));
            return sb.ToString();
        }
    }

    public class DependencyInfo
    {
        public string DependencyType { get; set; }
        public string DependencyValue { get; set; }

        public override string ToString()
        {
            const string tab4 = "@tab@@tab@@tab@@tab@";
            return (tab4 + string.Format("<dependency type=\"{0}\">{1}</dependency>", this.DependencyType, this.DependencyValue));
        }
    }

    public class ScriptInfo
    {
        public ScriptType Type { get; set; }
        public string FileName { get; set; }
        public string Version { get; set; }
        public string Path { get; set; }

        public override string ToString()
        {
            const string tab6 = "@tab@@tab@@tab@@tab@@tab@@tab@";
            const string tab7 = "@tab@@tab@@tab@@tab@@tab@@tab@@tab@";

            //Build the element
            StringBuilder sb = new StringBuilder();

            sb.AppendLine(tab6 + "<script type=\"" + this.Type.ToString() + "\">");
            if (!string.IsNullOrEmpty(Path))
                sb.AppendLine(tab7 + "<path>" + Path + "</path>");
            sb.AppendLine(tab7 + "<name>" + this.FileName + "</name>");
            if (this.Type != ScriptType.Uninstall)
                sb.AppendLine(tab7 + "<version>" + this.Version + "</version>");
            sb.Append(tab6 + "</script>");
            return sb.ToString();
        }
    }

    public class CleanUpInfo
    {
        public string Version { get; set; }
        public string FileName { get; set; }

        public override string ToString()
        {
            return string.Format("<component type=\"Cleanup\" version=\"{0}\" fileName=\"Installation\\CleanUp\\{1}\" />", Version, FileName);
        }
    }

    public class ModuleControlInfo
    {
        public string Name { get; set; }
        public string FileName { get; set; }
        public string Key { get; set; }
        public string Title { get; set; }
        public ControlType ControlType { get; set; }
        public string HelpUrl { get; set; }
        public string SupportsPopups { get; set; }
        public string SupportsAjax { get; set; }

        public override string ToString()
        {
            //Write Element
            const string tab9 = "@tab@@tab@@tab@@tab@@tab@@tab@@tab@@tab@@tab@";
            const string tab10 = "@tab@@tab@@tab@@tab@@tab@@tab@@tab@@tab@@tab@@tab@";

            StringBuilder sb = new StringBuilder();

            //<moduleControl>
            //  <controlKey></controlKey>
            //  <controlSrc>DesktopModules/MSBuildTestModule/YOURVIEW.ascx</controlSrc>
            //  <supportsPartialRendering>True</supportsPartialRendering>
            //  <supportsPopUps>True</supportsPopUps>       Note: Optional argument
            //  <controlTitle></controlTitle>
            //  <controlType>View</controlType>
            //  <helpUrl></helpUrl>
            //</moduleControl>

            sb.AppendLine(tab9 + "<moduleControl>");
            sb.AppendLine(tab10 + (Key == String.Empty ? "<controlKey />" : String.Format("<controlKey>{0}</controlKey>", Key)));
            sb.AppendLine(tab10 + String.Format("<controlSrc>DesktopModules/{0}/{1}</controlSrc>", Name, FileName));
            sb.AppendLine(tab10 + String.Format("<supportsPartialRendering>{0}</supportsPartialRendering>", SupportsAjax));

            // supportsPopUp is optional to support DNN5 install manifests
            if (this.SupportsPopups != "")
                sb.AppendLine(tab10 + String.Format("<supportsPopUps>{0}</supportsPopUps>", SupportsPopups));

            sb.AppendLine(tab10 + (Title == String.Empty ? "<controlTitle />" : String.Format("<controlTitle>{0}</controlTitle>", Title)));
            sb.AppendLine(tab10 + String.Format("<controlType>{0}</controlType>", ControlType));
            sb.AppendLine(tab10 + (HelpUrl == String.Empty ? "<helpUrl />" : String.Format("<helpUrl>{0}</helpUrl>", HelpUrl)));
            sb.Append(tab9 + "</moduleControl>");
            return sb.ToString();
        }
    }

    public class PackageInfo
    {
        public PackageInfo()
        {
            Order = 0;
            LicenseFile = "License.txt";
            Modules = new List<ModuleInfo>();
            Dependencies = new List<DependencyInfo>();
            Scripts = new List<ScriptInfo>();
            Assemblies = new List<AssemblyInfo>();
            CleanUp = new List<CleanUpInfo>();
            Config = new ConfigEntriesInfo();
        }
        public int Order { get; set; }
        public string Name { get; set; }
        public string Version { get; set; }
        public string FriendlyName { get; set; }
        public string FolderName { get; set; }
        public string Description { get; set; }
        public string IconFile { get; set; }
        public string OwnerName { get; set; }
        public string OwnerOrganization { get; set; }
        public string OwnerUrl { get; set; }
        public string OwnerEmail { get; set; }
        public string LicenseFile { get; set; }
        public string ReleaseNotes { get; set; }
        public string AzureCompatible { get; set; }
        public List<DependencyInfo> Dependencies { get; set; }
        public List<ModuleInfo> Modules { get; set; }
        public List<ScriptInfo> Scripts { get; set; }
        public List<AssemblyInfo> Assemblies { get; set; }
        public List<CleanUpInfo> CleanUp { get; set; }
        public ConfigEntriesInfo Config { get; set; }
        public bool IncludeResource { get; set; }


        public override string ToString()
        {
            const string tab2 = "@tab@@tab@";
            const string tab3 = "@tab@@tab@@tab@";
            const string tab4 = "@tab@@tab@@tab@@tab@";
            const string tab5 = "@tab@@tab@@tab@@tab@@tab@";
            const string tab6 = "@tab@@tab@@tab@@tab@@tab@@tab@";
            const string tab7 = "@tab@@tab@@tab@@tab@@tab@@tab@@tab@";

            StringBuilder sb = new StringBuilder();
            sb.AppendLine(tab2 + String.Format("<package name=\"{0}\" type=\"Module\" version=\"{1}\">", Name, Version));
            sb.AppendLine(tab3 + String.Format("<friendlyName>{0}</friendlyName>", FriendlyName));
            sb.AppendLine(tab3 + String.Format("<description>{0}</description>", Description));
            if (IconFile != string.Empty)
                sb.AppendLine(tab3 + String.Format("<iconFile>DesktopModules\\{0}\\{1}</iconFile>", FolderName, IconFile));
            sb.AppendLine(tab3 + "<owner>");
            sb.AppendLine(tab4 + String.Format("<name>{0}</name>", OwnerName));
            sb.AppendLine(tab4 + String.Format("<organization>{0}</organization>", OwnerOrganization));
            sb.AppendLine(tab4 + String.Format("<url>{0}</url>", OwnerUrl));
            sb.AppendLine(tab4 + String.Format("<email>{0}</email>", OwnerEmail));
            sb.AppendLine(tab3 + "</owner>");
            sb.AppendLine(tab3 + String.Format("<license src=\"{0}\"></license>", LicenseFile));
            if (ReleaseNotes != string.Empty)
                sb.AppendLine(tab3 + String.Format("<releaseNotes src=\"{0}\"></releaseNotes>", ReleaseNotes));
            sb.AppendLine(tab3 + String.Format("<azureCompatible>{0}</azureCompatible>", AzureCompatible));
            if (Dependencies.Count > 0)
            {
                sb.AppendLine(tab3 + "<dependencies>");
                foreach (DependencyInfo dependency in Dependencies)
                {
                    sb.AppendLine(dependency.ToString());
                }
                sb.AppendLine(tab3 + "</dependencies>");
            }
            sb.AppendLine(tab3 + "<components>");
            if (Scripts.Count > 0)
            {
                sb.AppendLine(tab4 + "<component type=\"Script\">");
                sb.AppendLine(tab5 + "<scripts>");
                sb.AppendLine(tab6 + String.Format("<basePath>DesktopModules\\{0}</basePath>", FolderName));
                foreach (ScriptInfo script in Scripts)
                {
                    sb.AppendLine(script.ToString());
                }
                sb.AppendLine(tab5 + "</scripts>");
                sb.AppendLine(tab4 + "</component>");
            }

            foreach (ModuleInfo module in Modules)
            {
                sb.AppendLine(module.ToString());
            }
            if (Assemblies.Count > 0)
            {
                sb.AppendLine(tab4 + "<component type=\"Assembly\">");
                sb.AppendLine(tab5 + "<assemblies>");
                foreach (AssemblyInfo assembly in Assemblies)
                {
                    sb.AppendLine(assembly.ToString());
                }
                sb.AppendLine(tab5 + "</assemblies>");
                sb.AppendLine(tab4 + "</component>");
            }
            if (IncludeResource)
            {
                sb.AppendLine(tab4 + "<component type=\"ResourceFile\">");
                sb.AppendLine(tab5 + "<resourceFiles>");
                sb.AppendLine(tab6 + String.Format("<basePath>DesktopModules\\{0}</basePath>", FolderName));
                sb.AppendLine(tab6 + "<resourceFile>");
                sb.AppendLine(tab7 + "<name>resources.zip</name>");
                sb.AppendLine(tab7 + "<sourceFileName>resources.zip</sourceFileName>");
                sb.AppendLine(tab6 + "</resourceFile>");
                sb.AppendLine(tab5 + "</resourceFiles>");
                sb.AppendLine(tab4 + "</component>");
            }
            foreach (CleanUpInfo cleanUp in CleanUp)
            {
                sb.AppendLine(tab4 + cleanUp.ToString());
            }
            sb.AppendLine(Config.ToString());
            sb.AppendLine(tab3 + "</components>");
            sb.Append(tab2 + "</package>");
            return sb.ToString();
        }
    }

    public class ModuleInfo
    {
        public ModuleInfo()
        {
            ModuleControls = new List<ModuleControlInfo>();
            ModulePermissions = new List<ModulePermissionInfo>();
        }
        public string ModuleName { get; set; }
        public string FriendlyName { get; set; }
        public string FolderName { get; set; }
        public string DefaultCacheTime { get; set; }
        public BusinessControllerInfo BusinessController { get; set; }
        public List<ModuleControlInfo> ModuleControls { get; set; }
        public SupportedFeaturesInfo SupportedFeatures { get; set; }
        public EventMessageInfo EventMessage { get; set; }
        public List<ModulePermissionInfo> ModulePermissions { get; set; }

        public override string ToString()
        {
            const string tab2 = "@tab@@tab@";
            const string tab3 = "@tab@@tab@@tab@";
            const string tab4 = "@tab@@tab@@tab@@tab@";
            const string tab5 = "@tab@@tab@@tab@@tab@@tab@";
            const string tab6 = "@tab@@tab@@tab@@tab@@tab@@tab@";
            const string tab7 = "@tab@@tab@@tab@@tab@@tab@@tab@@tab@";
            const string tab8 = "@tab@@tab@@tab@@tab@@tab@@tab@@tab@@tab@";

            StringBuilder sb = new StringBuilder();
            sb.AppendLine(tab4 + "<component type=\"Module\">");
            sb.AppendLine(tab5 + "<desktopModule>");
            sb.AppendLine(tab6 + String.Format("<moduleName>{0}</moduleName>", ModuleName));
            sb.AppendLine(tab6 + String.Format("<foldername>{0}</foldername>", FolderName));
            sb.AppendLine(BusinessController.ToString());
            sb.AppendLine(SupportedFeatures.ToString());
            sb.AppendLine(tab6 + "<moduleDefinitions>");
            sb.AppendLine(tab7 + "<moduleDefinition>");
            sb.AppendLine(tab8 + String.Format("<friendlyName>{0}</friendlyName>", FriendlyName));
            sb.AppendLine(tab8 + String.Format("<defaultCacheTime>{0}</defaultCacheTime>", DefaultCacheTime));
            if (ModuleControls.Any())
            {
                sb.AppendLine(tab8 + "<moduleControls>");
                foreach (ModuleControlInfo moduleControl in ModuleControls.OrderBy(m => m.Key).ToList())
                {
                    sb.AppendLine(moduleControl.ToString());
                }
                sb.AppendLine(tab8 + "</moduleControls>");
            }
            if (ModulePermissions.Any())
            {
                sb.AppendLine(tab8 + "<permissions>");
                foreach (ModulePermissionInfo modulePermission in ModulePermissions)
                {
                    sb.AppendLine(ModulePermissions.ToString());
                }
                sb.AppendLine(tab8 + "</permissions>");
            }
            sb.AppendLine(tab7 + "</moduleDefinition>");
            sb.AppendLine(tab6 + "</moduleDefinitions>");
            sb.Append(tab5 + "</desktopModule>");
            if (EventMessage != null)
                sb.AppendLine(EventMessage.ToString());
            sb.Append(tab4 + "</component>");
            return sb.ToString();
        }
    }

    public class SupportedFeaturesInfo
    {
        public SupportedFeaturesInfo()
        {
            Features = new List<string>();
        }

        public List<string> Features { get; set; }

        public override string ToString()
        {
            const string tab7 = "@tab@@tab@@tab@@tab@@tab@@tab@@tab@";
            const string tab6 = "@tab@@tab@@tab@@tab@@tab@@tab@";

            if (!Features.Any())
                return tab6 + "<supportedFeatures />";
            else
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine(tab6 + "<supportedFeatures>");
                foreach (string feature in Features)
                {
                    sb.AppendLine(tab7 + "<supportedFeature type=\"" + feature + "\" />");
                }

                sb.Append(tab6 + "</supportedFeatures>");
                return sb.ToString();
            }
        }

    }
    /// <summary>
    /// Task to create the DNN file
    /// </summary>
    public class CreateDnnFile : Task
    {
        #region Private Members

        private List<PackageInfo> Packages = new List<PackageInfo>();
        private List<AssemblyInfo> Assemblies = new List<AssemblyInfo>();
        private List<DependencyInfo> Dependencies = new List<DependencyInfo>();
        private List<ScriptInfo> Scripts = new List<ScriptInfo>();
        private ConfigEntriesInfo Config = new ConfigEntriesInfo();
        private List<CleanUpInfo> CleanUps = new List<CleanUpInfo>();
        private string ReleaseNotes = "";

        private string ResultString;

        #endregion

        #region Properties

        public string AssemblyPath { get; set; }
        public string ScriptPath { get; set; }
        public string ModulePath { get; set; }

        [Required]
        public string Target { get; set; }

        [Required]
        public string Version { get; set; }

        [Required]
        public ITaskItem[] AssemblyFiles { get; set; }

        [Required]
        public ITaskItem[] CodeFiles { get; set; }

        [Required]
        public ITaskItem[] ScriptFiles { get; set; }

        [Required]
        public ITaskItem[] CleanUpFiles { get; set; }

        [Required]
        public ITaskItem[] ConfigFiles { get; set; }

        [Required]
        public ITaskItem[] ReleaseFiles { get; set; }

        #endregion

        #region Events

        public override bool Execute()
        {
            try
            {
                ParseFiles();
                ResultString = BuildOutput();

                //If string is null, return an empty string "", It may not be null!
                if (string.IsNullOrEmpty(ResultString)) ResultString = "@tab@";

                //Output the file
                StreamWriter sw = new StreamWriter(Target, false);
                sw.Write(ResultString);
                sw.Close();

                return true;
            }
            catch (Exception ex)
            {
                Log.LogErrorFromException(ex);
                return false;
            }
        }

        #endregion

        #region Private Methods

        private void ParseFiles()
        {
            #region ReleaseNotes
            //For each assembly file
            foreach (ITaskItem releaseFile in ReleaseFiles)
            {
                //Get the File properties
                string file = releaseFile.ItemSpec;
                string fileName = System.IO.Path.GetFileName(file);
                if (fileName.Contains(Version))
                {
                    ReleaseNotes = fileName;
                    break;
                }
            }

            #endregion

            #region Assemblyfiles
            //For each assembly file
            foreach (ITaskItem assemblyFile in AssemblyFiles)
            {
                //Get the File properties
                string file = assemblyFile.ItemSpec;
                string fileName = System.IO.Path.GetFileName(file);
                AssemblyInfo assembly = new AssemblyInfo();
                assembly.FileName = fileName;
                assembly.Path = AssemblyPath;
                Assemblies.Add(assembly);
            }

            #endregion

            #region Scriptfiles
            //For each script file
            foreach (ITaskItem item in ScriptFiles)
            {
                //Get the File properties
                string file = item.ItemSpec;
                string fileName = System.IO.Path.GetFileName(file);
                string scriptName = System.IO.Path.GetFileNameWithoutExtension(file);
                string version = scriptName;
                string scriptType = scriptName.ToLower() == "uninstall" ? "Uninstall" : "Install";

                // Is this a clean install script for a particular version? 
                // Format: install.nn.nn.nn.SqlDataProvider
                if ((scriptType == "Install") && (scriptName.Substring(0, 8).ToLower() == "install."))
                    version = scriptName.Substring(8);

                ScriptInfo script = new ScriptInfo();
                script.Type = (ScriptType)Enum.Parse(typeof(ScriptType), scriptType);
                script.FileName = fileName;
                script.Path = ScriptPath;
                script.Version = version;
                Scripts.Add(script);
            }

            #endregion

            #region Codefiles

            List<ModulePermissionInfo> modulePermissions = new List<ModulePermissionInfo>();
            EventMessageInfo EventMessage = new EventMessageInfo();
            SupportedFeaturesInfo supportedFeatures = new SupportedFeaturesInfo();
            BusinessControllerInfo BusinessController = new BusinessControllerInfo();

            //For each code file
            foreach (ITaskItem codeFile in CodeFiles)
            {
                //Read the file
                string file = codeFile.ItemSpec;
                string fileName = System.IO.Path.GetFileName(file);
                string nameSpace = "";
                bool found = false;
                bool controllerFound = false;
                string eventMessageVersions = "";
                string packageName = "";
                string moduleName = "";
                bool actionable = false, hydratable = false, portable = false, searchable = false, upgradeable = false;
                StreamReader sr = new StreamReader(file);
                string sline = "";
                ArrayList lines = new ArrayList();
                while (sline != null)
                {
                    sline = sr.ReadLine();
                    if (sline != null)
                        lines.Add(sline);
                }
                sr.Close();

                //Look into the file
                foreach (string line in lines)
                {
                    //If line is comment, ignore it.
                    if (line.Trim().StartsWith("'") || line.Trim().StartsWith("//") || line.Trim() == "")
                        continue;

                    //Get the namespace
                    if (line.Trim().ToLower().Contains("namespace"))
                    {
                        nameSpace = line.Replace("namespace", "").Replace("Namespace", "").Trim();
                    }

                    //If line contains DNNtc.BusinessControllerClass the next line contains the class name
                    if (line.Trim().Contains("DNNtc.BusinessControllerClass"))
                    {
                        //When Found, Controller class is on the next line.(Can Only happen once)
                        found = true;
                        continue;
                    }

                    //When found, complete the resultstring and stop iterating all
                    if (line.Trim().ToLower().Contains("class") && found)
                    {
                        BusinessController = new BusinessControllerInfo();
                        BusinessController.Class = nameSpace + "." + line.Trim().Split(' ')[2].Trim();
                        BusinessController.NameSpace = nameSpace.Trim();

                        controllerFound = true;
                        found = false;
                    }

                    //If line contains DNNtc.BusinessControllerClass the next line contains the class name
                    if (line.Trim().Contains("DNNtc.UpgradeEventMessage"))
                    {
                        //Construct the EventMessage
                        string versionList = line.Trim().Substring(1);
                        versionList = versionList.Replace("DNNtc.UpgradeEventMessage(", "");
                        versionList = versionList.Replace(")]", "");
                        versionList = versionList.Replace(")> _", "");
                        versionList = versionList.Replace("\"", "");
                        eventMessageVersions = versionList;
                    }

                    //Add implementations
                    if (controllerFound && (line.Trim().Contains(":") || line.Trim().Contains("Implements")))
                    {

                        //Build features
                        if (line.Trim().Contains("IActionable") && !actionable)
                        {
                            supportedFeatures.Features.Add("Actionable");
                            actionable = true;
                        }

                        if (line.Trim().Contains("IHydratable") && !hydratable)
                        {
                            supportedFeatures.Features.Add("Hydratable");
                            hydratable = true;
                        }

                        if (line.Trim().Contains("IPortable") && !portable)
                        {
                            supportedFeatures.Features.Add("Portable");
                            portable = true;
                        }

                        if (line.Trim().Contains("ISearchable") && !searchable)
                        {
                            supportedFeatures.Features.Add("Searchable");
                            searchable = true;
                        }

                        if (line.Trim().Contains("IUpgradeable") && !upgradeable)
                        {
                            supportedFeatures.Features.Add("Upgradeable");
                            upgradeable = true;

                            //When Upgradeble, add the EventMessage
                            EventMessage = new EventMessageInfo();
                            EventMessage.BusinessController = BusinessController.Class;
                            EventMessage.UpgradeVersionsList = eventMessageVersions;
                        }
                    }

                    if (line.Trim().Contains("DNNtc.ModulePermission"))
                    {
                        string elements = line.Trim();

                        elements = elements.Substring(1);
                        elements = elements.Replace("DNNtc.ModulePermission(", "");
                        elements = elements.Replace(")]", "");
                        elements = elements.Replace(")> _", "");
                        elements = elements.Replace("\"", "");

                        //Get the elements
                        string[] properties = elements.Split(',');
                        string code = properties[0].Trim();
                        string key = properties[1].Trim();
                        string name = properties[2].Trim();

                        ModulePermissionInfo modulePermission = new ModulePermissionInfo();
                        modulePermission.Code = code;
                        modulePermission.Key = key;
                        modulePermission.Name = name;
                        modulePermissions.Add(modulePermission);
                    }

                    if (line.Trim().Contains("DNNtc.ModuleDependencies"))
                    {
                        string elements = line.Trim();

                        elements = elements.Substring(1);
                        elements = elements.Replace("DNNtc.ModuleDependencies(", "");
                        elements = elements.Replace(")]", "");
                        elements = elements.Replace(")> _", "");
                        elements = elements.Replace("\"", "");
                        elements = elements.Replace("DNNtc.ModuleDependency.", "");

                        string[] dependencies = elements.Split(',');
                        string dtype = dependencies[0].Trim();
                        string dvalue = dependencies[1].Trim();

                        if (dtype != String.Empty && dvalue != String.Empty)
                        {
                            DependencyInfo dependency = new DependencyInfo();
                            dependency.DependencyType = dtype;
                            dependency.DependencyValue = dvalue;
                            Dependencies.Add(dependency);
                        }
                        continue;
                    }


                    if (line.Trim().Contains("DNNtc.PackageProperties"))
                    {
                        //Found the Attribute. Now read the settings
                        // [DNNtc.PackageProperties("Package_DNNTctest","DNNTcTest Paket")]
                        string elements = line.Trim();

                        elements = elements.Substring(1);
                        elements = elements.Replace(@"""", " ");
                        elements = elements.Replace("DNNtc.PackageProperties(", "");
                        elements = elements.Replace(")]", "");
                        elements = elements.Replace("]", "");
                        elements = elements.Replace(")> _", "");
                        elements = elements.Replace("\"", "");

                        string description = "",
                            friendlyName = "",
                            iconFile = "",
                            ownerName = "",
                            ownerOrg = "",
                            ownerUrl = "",
                            ownerEmail = "";
                        bool azureCompatible = false;

                        int order = -1;

                        //Get the elements
                        string[] properties = elements.Split(',');
                        int propCount = properties.Count();

                        packageName = properties[0].Trim();
                        if (propCount > 1)
                        {
                            order = Convert.ToInt32(properties[1].Trim());
                            friendlyName = properties[2].Trim();

                            // if we have a "," in description, we need to take care !
                            if (propCount > 10)
                            {
                                description = properties[3].Trim();
                                for (int i = 4; i < propCount - 6; i++)
                                {
                                    description += "," + properties[i];
                                }
                            }
                            else
                                description = properties[3].Trim();

                            iconFile = properties[propCount - 6].Trim();
                            ownerName = properties[propCount - 5].Trim();
                            ownerOrg = properties[propCount - 4].Trim();
                            ownerUrl = properties[propCount - 3].Trim();
                            ownerEmail = properties[propCount - 2].Trim();
                            azureCompatible = Convert.ToBoolean(properties[propCount - 1].Trim());
                        }

                        PackageInfo package = Packages.Find(p => p.Name == packageName);
                        if (package == null)
                        {
                            package = new PackageInfo();
                            Packages.Add(package);
                            package.ReleaseNotes = ReleaseNotes;
                            package.FolderName = ModulePath;
                            package.Name = packageName;
                            package.Version = Version;
                        }

                        if (propCount > 1)
                        {
                            package.FriendlyName = friendlyName;
                            package.Description = description;
                            package.IconFile = iconFile;
                            package.OwnerName = ownerName;
                            package.OwnerOrganization = ownerOrg;
                            package.OwnerUrl = ownerUrl;
                            package.OwnerEmail = ownerEmail;
                            package.Order = order;
                            package.AzureCompatible = azureCompatible.ToString();
                        }
                        continue;
                    }

                    if (line.Trim().Contains("DNNtc.ModuleProperties"))
                    {
                        //Found the Attribute. Now read the settings
                        // [DNNtc.ModuleProperties("Modul_DNNTcText", "DNNTcTest Modul", -1)]
                        // or
                        // [DNNtc.ModuleProperties("Modul_DNNTcText")]
                        string elements = line.Trim();

                        elements = elements.Substring(1);
                        elements = elements.Replace(@"""", " ");
                        elements = elements.Replace("DNNtc.ModuleProperties(", "");
                        elements = elements.Replace(")]", "");
                        elements = elements.Replace(")> _", "");
                        elements = elements.Replace("\"", "");

                        string friendlyName = "", defaultCacheTime = "";

                        //Get the elements
                        string[] properties = elements.Split(',');
                        int propCount = properties.Count();

                        moduleName = properties[0].Trim();

                        if (propCount > 1)
                        {
                            friendlyName = properties[1].Trim();
                            defaultCacheTime = properties[2].Trim();
                        }

                        PackageInfo package = Packages.Find(p => p.Name == packageName);
                        ModuleInfo module = package.Modules.Find(m => m.ModuleName == moduleName);
                        if (module == null)
                        {
                            module = new ModuleInfo();
                            module.ModuleName = moduleName;
                            module.FolderName = ModulePath;
                            module.ModulePermissions = modulePermissions;
                            package.Modules.Add(module);
                        }

                        if (propCount > 1)
                        {
                            module.FriendlyName = friendlyName;
                            module.DefaultCacheTime = defaultCacheTime;
                        }
                        continue;
                    }


                    if (line.Trim().Contains("DNNtc.ModuleControlProperties"))
                    {
                        //Found the Attribute. Now read the settings
                        //Package, Key, Title, Controltype, HelpUrl, SupportsPartialRendering
                        string elements = line.Trim();

                        elements = elements.Substring(1);
                        elements = elements.Replace(@"""", " ");
                        elements = elements.Replace("DNNtc.ModuleControlProperties(", "");
                        elements = elements.Replace(")]", "");
                        elements = elements.Replace(")> _", "");
                        elements = elements.Replace("\"", "");
                        elements = elements.Replace("DNNtc.ControlType.", "");

                        //Get the elements
                        string[] properties = elements.Split(',');
                        string key = properties[0].Trim();
                        string title = properties[1].Trim();
                        string controlType = properties[2].Trim();
                        string helpUrl = properties[3].Trim();
                        string supAjax = properties[4].Trim();

                        // To be compliant with DNN5, the supportsPopUp argument is optional
                        string supPopUp = "";

                        if (properties.Length > 5)
                            supPopUp = properties[5].Trim();

                        ModuleControlInfo modControl = new ModuleControlInfo();
                        modControl.Key = key;
                        modControl.Name = ModulePath;
                        modControl.FileName = fileName.Replace(".cs", "");
                        modControl.Title = title;
                        modControl.ControlType = (ControlType)Enum.Parse(typeof(ControlType), controlType, true);
                        modControl.HelpUrl = helpUrl;
                        modControl.SupportsAjax = supAjax;
                        modControl.SupportsPopups = supPopUp;

                        PackageInfo package = Packages.Find(p => p.Name == packageName);
                        ModuleInfo module = package.Modules.Find(m => m.ModuleName == moduleName);
                        module.ModuleControls.Add(modControl);
                    }
                }
            }

            foreach (PackageInfo package in Packages)
            {
                foreach (ModuleInfo module in package.Modules)
                {
                    module.SupportedFeatures = supportedFeatures;
                    module.BusinessController = BusinessController;
                    module.EventMessage = EventMessage;
                }
            }


            #endregion

            #region Configfiles
            //For each config file
            foreach (ITaskItem item in ConfigFiles)
            {
                //Read the file
                string file = item.ItemSpec;
                ArrayList lines = new ArrayList();
                if (File.Exists(file))
                {
                    StreamReader sr = new StreamReader(file);
                    string sline = "";
                    while (sline != null)
                    {
                        sline = sr.ReadLine();
                        if (sline != null)
                            lines.Add(sline);
                    }
                    sr.Close();
                }

                //Look into the file
                foreach (string line in lines)
                {
                    if (line.StartsWith("'") || line.StartsWith("//") || string.IsNullOrEmpty(line)) continue;

                    //Get the values seperated
                    string[] cs = line.Split(':');

                    ConfigInfo config = new ConfigInfo();

                    //Fill values
                    config.Path = cs[0];
                    config.Action = cs[1];
                    string[] type = cs[2].Split('=');
                    config.Key = type[0];
                    config.Value = type[1];
                    config.Ros = cs[3];
                    config.Collision = cs[4].Split('=')[1];
                    Config.Add(config);
                }
            }

            #endregion

            #region CleanupFiles
            //For each config file
            foreach (ITaskItem item in CleanUpFiles)
            {
                //Get the File properties
                string file = item.ItemSpec;
                string fileName = System.IO.Path.GetFileName(file);
                CleanUpInfo cleanUp = new CleanUpInfo();
                cleanUp.FileName = fileName;
                cleanUp.Version = fileName.ToUpper().Replace(".TXT", "").Replace("CLEANUP.", "");
                CleanUps.Add(cleanUp);
            }
            #endregion
        }

        private string BuildOutput()
        {
            const string tab1 = "@tab@";
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("<dotnetnuke type=\"Package\" version=\"5.0\">");
            sb.AppendLine(tab1 + "<packages>");

            bool first = true;

            foreach (PackageInfo package in Packages.OrderBy(p => p.Order).ToList())
            {
                if (first)
                {
                    package.Assemblies = Assemblies;
                    package.Dependencies = Dependencies;
                    package.Scripts = Scripts;
                    package.Config = Config;
                    package.CleanUp = CleanUps;
                    package.IncludeResource = true;
                }

                sb.AppendLine(package.ToString());
                first = false;
            }
            sb.AppendLine(tab1 + "</packages>");
            sb.AppendLine("</dotnetnuke>");

            // Do the the formatting
            sb.Replace("@tab@", "  ");
            return sb.ToString();
        }

        #endregion
    }

    /// <summary>
    /// Component to compress all scripts.
    /// </summary>
    public class CompressScriptComponent : Task
    {
        #region Properties

        /// <summary>
        /// An array of script files to compress
        /// </summary>
        [Required]
        public ITaskItem[] Files { get; set; }

        /// <summary>
        /// Enable compression or not.
        /// </summary>
        [Required]
        public string EnableCompression { get; set; }

        /// <summary>
        /// Set Logging parameter
        /// </summary>
        [Required]
        public string IsVerboseLogging { get; set; }

        /// <summary>
        /// Set obfuscate Javascript parameter
        /// </summary>
        [Required]
        public string IsObfuscateJavascript { get; set; }

        /// <summary>
        /// Set preserve all semicolons parameter
        /// </summary>
        [Required]
        public string PreserveAllSemicolons { get; set; }

        /// <summary>
        /// Disable script optimizations parameter
        /// </summary>
        [Required]
        public string DisableOptimizations { get; set; }

        /// <summary>
        /// Set the linebreak position parameter
        /// </summary>
        [Required]
        public int LineBreakPosition { get; set; }

        /// <summary>
        /// Set the encoding type parameter
        /// </summary
        public string Encoding { get; set; }

        /// <summary>
        /// Set the thread culture parameter
        /// </summary>
        public string ThreadCulture { get; set; }

        /// <summary>
        /// Set the Is eval function parameter
        /// </summary>
        [Required]
        public string IsEvalIgnored { get; set; }

        /// <summary>
        /// Output string for MSBuild.
        /// </summary>
        [Output]
        public string ResultString { get; set; }

        #endregion

        #region Events

        /// <summary>
        /// Execute the build Config output for the Javascript compressor.
        /// </summary>
        /// <returns></returns>
        public override bool Execute()
        {
            try
            {
                //Build output
                BuildConfigOutput();

                return true;
            }
            catch (Exception ex)
            {
                Log.LogErrorFromException(ex);
                return false;
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Build config output for the Javascript compressor
        /// </summary>
        private void BuildConfigOutput()
        {

            bool isCompressioneEnabled = true;
            Boolean.TryParse(EnableCompression, out isCompressioneEnabled);

            if (isCompressioneEnabled == false)
            {
                return;
            }


            bool isVerboseLogging;
            Boolean.TryParse(IsVerboseLogging, out isVerboseLogging);

            bool isObfuscateJavascript;
            Boolean.TryParse(IsObfuscateJavascript, out isObfuscateJavascript);

            bool preserveAllSemicolons;
            Boolean.TryParse(PreserveAllSemicolons, out preserveAllSemicolons);

            bool disableOptimizations;
            Boolean.TryParse(DisableOptimizations, out disableOptimizations);

            // Set default compression, if entered value by user in Project.Targets file is incorrect.
            Encoding encoding;

            // Choose the encoding type.
            switch (Encoding)
            {
                case "Default":
                case "":
                    encoding = System.Text.Encoding.Default;
                    break;
                case "ASCII":
                    encoding = System.Text.Encoding.ASCII;
                    break;
                case "UTF7":
                    encoding = System.Text.Encoding.UTF7;
                    break;
                case "UTF8":
                    encoding = System.Text.Encoding.UTF8;
                    break;
                case "UTF32":
                    encoding = System.Text.Encoding.UTF32;
                    break;
                case "Unicode":
                    encoding = System.Text.Encoding.Unicode;
                    break;
                default:
                    try
                    {
                        encoding = System.Text.Encoding.GetEncoding(Encoding);

                    }
                    catch (ArgumentException)
                    {
                        encoding = System.Text.Encoding.Default;

                    }

                    break;
            }

            // Set default to currentculture
            CultureInfo cultureInfo = CultureInfo.CurrentCulture;

            // Is the user specified the culture, try to parse it.
            if (!string.IsNullOrEmpty(ThreadCulture))
            {
                cultureInfo = CultureInfo.GetCultureInfo(ThreadCulture);
            }

            bool isEvalIgnored;
            Boolean.TryParse(IsEvalIgnored, out isEvalIgnored);

            //For each file
            foreach (ITaskItem item in Files)
            {

                //Read the file
                string scriptFileContent = File.ReadAllText(item.ItemSpec);

                string scriptFileCompressed = JavaScriptCompressor.Compress(scriptFileContent, isVerboseLogging, isObfuscateJavascript, preserveAllSemicolons, disableOptimizations, LineBreakPosition, encoding, cultureInfo, isEvalIgnored);

                using (StreamWriter outputFile = new StreamWriter(item.ItemSpec))
                {
                    outputFile.Write(scriptFileCompressed);
                }
            }
        }

        #endregion

    }


    /// <summary>
    /// Component to compress all css files.
    /// </summary>
    public class CompressCssComponent : Task
    {
        #region Properties

        /// <summary>
        /// An array of script files to compress
        /// </summary>
        [Required]
        public ITaskItem[] Files { get; set; }

        /// <summary>
        /// Enable compression or not.
        /// </summary>
        [Required]
        public string EnableCompression { get; set; }

        /// <summary>
        /// Set the linebreak position parameter
        /// </summary>
        [Required]
        public int LineBreakPosition { get; set; }

        /// <summary>
        /// Set the compression type parameter.
        /// </summary>
        [Required]
        public string CompressionType { get; set; }

        /// <summary>
        /// Output string for MSBuild.
        /// </summary>
        [Output]
        public string ResultString { get; set; }

        #endregion

        #region Events

        /// <summary>
        /// Execute the build Config output for the CSS compressor.
        /// </summary>
        /// <returns></returns>
        public override bool Execute()
        {
            try
            {
                //Build output
                BuildConfigOutput();

                return true;
            }
            catch (Exception ex)
            {
                Log.LogErrorFromException(ex);
                return false;
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Build config output for CSS compressor
        /// </summary>
        private void BuildConfigOutput()
        {
            bool isCompressioneEnabled = true;
            Boolean.TryParse(EnableCompression, out isCompressioneEnabled);

            if (isCompressioneEnabled == false)
            {
                return;
            }


            //For each file
            foreach (ITaskItem item in Files)
            {
                //Read the file
                string cssFileContent = File.ReadAllText(item.ItemSpec);

                // Set default compression, if entered value by user in Project.Targets file is incorrect.
                CssCompressionType compressionType = CssCompressionType.StockYuiCompressor;

                // Try to parse the CompressionType value to the CssCompressionType
                if (Enum.IsDefined(typeof(CssCompressionType), CompressionType))
                {
                    // Parse the user entered CompressionType.    
                    compressionType =
                        (CssCompressionType)Enum.Parse(typeof(CssCompressionType), CompressionType, true);
                }

                // Compress the file with the Yahoo.YUI compress lib.
                string cssFileCompressed = CssCompressor.Compress(cssFileContent, LineBreakPosition, compressionType);

                // Overwrite the original file with the minified file.
                using (StreamWriter outputFile = new StreamWriter(item.ItemSpec))
                {
                    outputFile.Write(cssFileCompressed);
                }
            }
        }

        #endregion
    }


    /// <summary>
    /// Component to format the resulting XML based .DNN file.
    /// </summary>
    public class FormatDnnXmlFileComponent : Task
    {
        #region Properties

        /// <summary>
        /// An array of files to process
        /// </summary>
        [Required]
        public ITaskItem[] DnnFiles { get; set; }

        /// <summary>
        /// Output string for MSBuild.
        /// </summary>
        [Output]
        public string ResultString { get; set; }

        #endregion

        #region Events

        /// <summary>
        /// Execute the build Config output for the CSS compressor.
        /// </summary>
        /// <returns></returns>
        public override bool Execute()
        {
            try
            {
                //Build output
                BuildConfigOutput();

                return true;
            }
            catch (Exception ex)
            {
                Log.LogErrorFromException(ex);
                return false;
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Formats the provided XML so it's indented and humanly-readable.
        /// </summary
        /// <returns></returns>
        private void BuildConfigOutput()
        {
            // Get the DNN file.
            ITaskItem dnnFile = DnnFiles[0];

            // Load the DNN file.
            XmlDocument document = new XmlDocument();
            document.Load(dnnFile.ItemSpec);

            // Make sure, the Xml declaration is not in the DNN file (and set indentation true).
            XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
            xmlWriterSettings.Indent = true;
            xmlWriterSettings.OmitXmlDeclaration = true;

            // Create a stringwriter to save the newly generated file.
            StringWriter stringWriter = new StringWriter();

            // Start a XmlWriter with the settings.
            using (XmlWriter writer = XmlWriter.Create(stringWriter, xmlWriterSettings))
            {
                // Save the document.
                document.Save(writer);
            }

            // Write the file.
            StreamWriter sw = new StreamWriter(dnnFile.ItemSpec, false);
            sw.Write(stringWriter.ToString());
            sw.Close();

            // Default resultstring.
            ResultString = " ";
        }

        #endregion

    }

}
